#!/usr/bin/python2.5
# -*- coding: utf-8 -*-

import cPickle
import os.path
import pdb
import sys
import wx
import wx.lib.imagebrowser as imagebrowser
import wx.xrc as xrc

PROGRAM = 'Terrain Painter'
VERSION = 0.1
TITLE = PROGRAM + ' ' + str(VERSION)
TILE_PATH = '../data/tptiles'

TERRAIN = [
	"001 - Plains",
	"002 - Rough Ground",
	"003 - Road",
	"004 - Forest",
	"005 - Mountain A",
	"006 - Mountain B",
	"007 - Ocean",
	"008 - Raised Wall",
	"009 - Castle Wall",
	"010 - Castle Interior",
	"011 - Home Interior",
	"012 - Temple Interior",
	"013 - Throne Room",
	"014 - Fishing Bridge",
	"015 - Sky Bridge",
	"016 - Plains",
	"017 - Burning",
	"018 - Burning",
	"019 - Graveyard",
	"020 - Ship Deck",
	"021 - Riverside",
	"022 - City Streets",
	"023 - Ship Deck",
	"024 - Riverside",
	"025 - City Streets",
	"026 - Realm of the Gods",
	"027 - Ruined Castle",
	"028 - High Wall",
	"029 - Forbidden"
]
wildcard = "PNG Image (*.png)|*.png|"	\
           "PCX Image (*.pcx)|*.pcx|"	\
           "GIF Image (*.gif)|*.gif|"	\
           "XPM Image (*.xpm)|*.xpm|"	\
           "JPEG Image (*.jpg)|*.jpg|"	\
           "Windows Bitmap (*.bmp)|*.bmp|"	\
           "All files (*.*)|*.*"

class Canvas(wx.Panel):
	def __init__(self, parent, bitmap):
		wx.Window.__init__(self, parent)
		self.x = self.y = 0
		# preserve original
		self.original = bitmap
		# create a copy
		self.bitmap = bitmap.GetSubBitmap((0, 0, bitmap.Width, bitmap.Height))
		self.Size = bitmap.Size
		self.Bind(wx.EVT_PAINT, self.onPaint)

	def onPaint(self, e):
		'''
		Used on move, resize or scroll events.
		Always paints the modified bitmap.
		'''
		dc = wx.PaintDC(self)
		dc.Clear()
		dc.DrawBitmap(self.bitmap, self.x, self.y, False)

	def draw(self, x, y, tile):
		'''
		Draw a tile to the internal bitmap,
		completely overwritting any previous tiles.
		'''
		dc = wx.MemoryDC(self.bitmap)
		original_chunk = self.original.GetSubBitmap((x, y, 48, 48))
		dc.DrawBitmap(original_chunk, x, y, False)
		dc.DrawBitmap(tile, x, y, True)
		'''
		Hard-refresh of the canvas.
		A better way would be to trigger the paint event.
		'''
		dc = wx.ClientDC(self)
		dc.DrawBitmap(self.bitmap, 0, 0, False)


class TerrainPainter(wx.App):
	def OnInit(self):
		self.toolidx = 0
		self.saved = True
		self.res = xrc.XmlResource('./terrpaintUI.xrc')
		self.frm = self.res.LoadFrame(None, 'MainFrame')
		self.frm.Title = TITLE
		self.scrolled = xrc.XRCCTRL(self.frm, 'container')
		self.chk_show_all = xrc.XRCCTRL(self.frm.GetToolBar(), 'chk_show_all')

		# main events
		self.frm.Bind(wx.EVT_CLOSE, self.onExit)
		self.frm.Bind(wx.EVT_MENU, self.onOpen, id=xrc.XRCID('menu_open'))
		self.frm.Bind(wx.EVT_TOOL, self.onOpen, id=xrc.XRCID('tool_open'))
		self.frm.Bind(wx.EVT_MENU, self.onSave, id=xrc.XRCID('menu_save'))
		self.frm.Bind(wx.EVT_TOOL, self.onSave, id=xrc.XRCID('tool_save'))
		self.frm.Bind(wx.EVT_MENU, self.onExit, id=xrc.XRCID('menu_exit'))
		self.frm.Bind(wx.EVT_CHECKBOX, self.onShowAllCheck, self.chk_show_all)
		self.frm.Bind(wx.EVT_CHOICE,
					self.onToolSelect,
					id=xrc.XRCID('chc_terrain'))

		self.frm.Show(True)
		return True

	def onOpen(self, e):
		if not self.saved and self.confirmClose() == wx.NO:
			return
		d = imagebrowser.ImageDialog(self.frm)
		if d.ShowModal() == wx.ID_OK:
			self.fullfilename = d.GetFile()
			self.openname = os.path.split(self.fullfilename)[1]
			bmp = wx.Bitmap(self.fullfilename, wx.BITMAP_TYPE_ANY)
			self.setScrolledCanvas(bmp)
			self.initMatrix()
			self.frm.Title = self.openname + ' - ' + TITLE
		d.Destroy()

	def onSave(self, e):
		file = open(self.fullfilename + '.cfg', 'wb')
		cPickle.dump(self.matrix, file)
		self.saved = True
		self.frm.Title = self.openname + ' - ' + TITLE

	def onExit(self, e):
		if not self.saved and self.confirmClose() == wx.NO:
			return False
		self.frm.Destroy()

	def onCanvasClick(self, e):
		self.handleClick(e)

	def onCanvasDrag(self, e):
		if e.LeftIsDown() and e.Dragging():
			self.handleClick(e)

	def onToolSelect(self, e):
		if self.toolidx != e.Selection:
			self.toolidx = e.Selection
			self.verifyRepaint()

	def onShowAllCheck(self, e):
		self.verifyRepaint()

	def confirmClose(self):
		return wx.MessageBox('The current file has unsaved changes. '
			'Do you wish to abandon those changes?', 'Warning',
			wx.YES_NO | wx.NO_DEFAULT | wx.ICON_EXCLAMATION)

	def setScrolledCanvas(self, bitmap):
		x, y = self.scrolled.CalcUnscrolledPosition(0, 0)
		self.scrolled.Scroll(0, 0)

		# create canvas
		self.canvas = Canvas(self.scrolled, bitmap)
		self.canvas.Bind(wx.EVT_LEFT_DOWN, self.onCanvasClick)
		self.canvas.Bind(wx.EVT_MOTION, self.onCanvasDrag)

		self.scrolled.SetVirtualSize(self.canvas.Size)
		(w, h) = self.canvas.Size
		self.scrolled.SetScrollRate(w // 100, h // 100)
		self.frm.Layout()
		self.scrolled.Scroll(x // (w // 100), y // (h // 100))

	def verifyRepaint(self):
		if self.chk_show_all.IsChecked():
			self.paintMatrix()
		else:
			self.setScrolledCanvas(self.canvas.original)
			self.paintMatrix(self.toolidx)

	def initMatrix(self):
		if os.path.isfile(self.fullfilename + '.cfg'):
			file = open(self.fullfilename + '.cfg', 'rb')
			self.matrix = cPickle.load(file)
			self.verifyRepaint()
		else:
			self.matrix = []
			for i in range(self.canvas.Size.x / 48):
				self.matrix.append([None for j in range(self.canvas.Size.y / 48)])

	def handleClick(self, e):
		tile_x = e.Position.x // 48
		tile_y = e.Position.y // 48

		self.drawTerrainAtTileXY(tile_x, tile_y, self.toolidx)
		self.matrix[tile_x][tile_y] = self.toolidx

		if self.saved:
			self.frm.Title = '*' + self.openname + ' - ' + TITLE
			self.saved = False

	def drawTerrainAtTileXY(self, x, y, toolidx):
		if toolidx is None:
			return
		strnum = str(toolidx + 1)
		if len(strnum) == 1:
			strnum = '0' + strnum
		imgname = TILE_PATH + '/terr' + strnum + '.png'
		bmp = wx.Bitmap(imgname, wx.BITMAP_TYPE_PNG)
		self.canvas.draw(x*48, y*48, bmp)

	def paintMatrix(self, just_this_tool = None):
		for i in range(len(self.matrix)):
			for j in range(len(self.matrix[i])):
				if (just_this_tool is None
					or self.matrix[i][j] == just_this_tool):
					self.drawTerrainAtTileXY(i, j, self.matrix[i][j])


# Initialization code and loop
if __name__ == '__main__':
	app = TerrainPainter()
	app.MainLoop()
